package com.losl.framework.aspect;

import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.losl.common.annotation.Log;
import com.losl.common.core.domain.Result;
import com.losl.common.core.domain.model.LoginUser;
import com.losl.common.enums.BusinessType;
import com.losl.common.enums.LogType;
import com.losl.common.exception.BaseException;
import com.losl.common.util.ServletUtils;
import com.losl.common.util.SpringUtils;
import com.losl.common.util.StringUtils;
import com.losl.framework.web.service.TokenService;
import com.losl.system.pojo.SysLog;
import com.losl.system.service.SysLogService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Date;
import java.util.stream.Collectors;

/**
 * Log
 */
@Component
@Aspect
@Slf4j
public class LogAspect {
    Logger logger = LoggerFactory.getLogger(LogAspect.class);

    @Autowired
    private SysLogService logService;

    /**
     * 切入点
     */
    @Pointcut("@annotation(com.losl.common.annotation.Log)")
    public void pointcut(){

    }

    @Around("pointcut()")
    public Object setLog(ProceedingJoinPoint joinPoint) throws Throwable {
        long beginTime = System.currentTimeMillis();
        SysLog sysLog = new SysLog();
        Object result = null;
        try {
            HttpServletRequest request = ServletUtils.getRequest();
            LoginUser loginUser = SpringUtils.getBean(TokenService.class).getLoginUser(request);
            sysLog.setUsername(loginUser.getUsername());

            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();
            String className=joinPoint.getTarget().getClass().getName();

            sysLog.setMethod(className+"."+signature.getName()+"()");

            Log log = method.getAnnotation(Log.class);
            BusinessType businessType = log.businessType();
            sysLog.setBusinessType(businessType.toString());

            String prefix1 = log.content();
            String prefix=prefix1 +" " +className+signature.getName()+"()";
            sysLog.setOperation(prefix1);

            String clientIP = ServletUtils.getClientIP(request);
            sysLog.setIp(clientIP);

            LogType logtype = log.logtype();
            Object collect = Arrays.stream(joinPoint.getArgs()).filter(obj ->
                    !(obj instanceof ServletRequest) && !(obj instanceof ServletResponse) && !(obj instanceof MultipartFile)
                            && !(obj instanceof HttpSession) && !(obj instanceof Model) && !(obj instanceof BindingResult))
                    .collect(Collectors.toList());
            Arrays.stream(joinPoint.getArgs()).forEach(System.out::println);
            String params = JSONUtil.toJsonStr(collect);
            sysLog.setParams(params);

            if (!LogType.PARAMETER.equals(logtype)){
                logger.info("<<<<<<,{},{}",prefix,params);
            }

            result = joinPoint.proceed();

            if (!LogType.RESULT.equals(logtype)){
                logger.info(">>>>>>,{},{}",prefix,JSON.toJSONString(result));
            }

            if (result instanceof Result){
                sysLog.setRetMsg(((Result) result).get("msg").toString());
                sysLog.setRetCode(((Result) result).get("code").toString());
            }else{
                sysLog.setRetCode("0");
                sysLog.setRetMsg(JSON.toJSONString(result));
            }

        } catch (Exception e) {
            if (e instanceof BaseException){
                BaseException be=(BaseException)e;
                sysLog.setParams(JSON.toJSONString(be.getArgs()));
                sysLog.setRetCode(be.getCode());
                sysLog.setRetMsg(be.getMessage());
                sysLog.setOperation(be.getModule());
                logger.info("<<<<<<,Excution method [{}] exception: {}",sysLog.getMethod(),be.getMessage());
            }else {
                sysLog.setRetCode("400");
                String message = e.getMessage();
                if (StringUtils.isNull(message)){
                     message = e.getCause().getMessage();
                }
                sysLog.setRetMsg(message);
                logger.info("<<<<<<,Excution method [{}] exception: {}",sysLog.getMethod(),message);
            }
            throw e;
        } finally {
            // 执行时长(毫秒)
            long time = System.currentTimeMillis() - beginTime;
            sysLog.setTime(time);
            sysLog.setCreateTime(new Date(System.currentTimeMillis()));
            System.out.println(sysLog);
            logService.save(sysLog);
        }
        return result;
    }

}
